<script setup lang="tsx">
import type { Ref } from 'vue';
import { h, reactive, ref, shallowRef } from 'vue';
import { useBoolean } from '@sa/hooks';
import { NButton, type TreeOption } from 'naive-ui';
import { $t } from '@/locales';
import { deleteMenu, listPages, treeMenu } from '@/service/api/manage';
import SvgIcon from '@/components/_builtin/svg-icon/index.vue';
import ButtonListTable from './modules/button-list-table.vue';
import MenuOperateDrawer, { type OperateType } from './modules/menu-operate-drawer.vue';

const { bool: menuVisible, setTrue: showMenu, setFalse: hideMenu } = useBoolean();

const { bool: buttonVisible, setBool: setButtonVisible, setFalse: hideButton } = useBoolean();

const { bool: menuDrawerVisible, setTrue: openMenuDrawer } = useBoolean();

const operateType = ref<OperateType>('add');

/** tree data */
const menuTree = shallowRef<TreeOption[]>([]);

/** tree pattern name , use tree search */
const name: Ref<string> = ref('');

/** the select menu data */
const showData = reactive<Api.Manage.Menu>({
  id: 0,
  type: 1,
  name: '',
  routeName: '',
  routePath: '',
  icon: '',
  iconType: '1',
  status: '1',
  hide: '0',
  iframeUrl: '',
  sort: 0,
  parentId: 0,
  component: undefined,
  children: undefined
});

/** get tree data */
async function getTree() {
  const data = await treeMenu();
  if (data) {
    menuTree.value = data.map(recursive);
  }
}

/** recursive menu tree data, add prefix transform treeOption format */
function recursive(item: Api.Node): TreeOption {
  const result: TreeOption = {
    ...item,
    children: item.children ? item.children.map(recursive) : undefined,
    prefix: () =>
      item.type === '1' ? h(<icon-material-symbols-folder-outline />) : h(<icon-material-symbols-list-alt-outline />)
  };

  return result;
}

/** tree select handle */
function handleSelectKeys(node: TreeOption | null, action: string) {
  if (node && action === 'select') {
    Object.assign(showData, node);
    showMenu();
    setButtonVisible(showData.type === 2);
  } else {
    Object.assign(showData.id, 0);

    hideMenu();
    hideButton();
  }
}

const allPages = shallowRef<string[]>([]);

async function getAllPages() {
  const pages = await listPages();
  allPages.value = pages || [];
}

function handleAddMenu() {
  operateType.value = 'add';
  openMenuDrawer();
}

function handleEditMenu() {
  operateType.value = 'edit';
  openMenuDrawer();
}

async function handleDeleteMenu() {
  const result = await deleteMenu({ id: showData.id });
  if (result) {
    window.$message?.success($t('common.deleteSuccess'));
    init(null);
    hideMenu();
    hideButton();
  }
}

function init(data: Api.Manage.Menu | null) {
  if (data) {
    Object.assign(showData, data);
  }

  // 可能是新增，查询刷新
  getTree();
  getAllPages();
}

init(null);
</script>

<template>
  <div class="flex">
    <NSplit :size="0.2" :resize-trigger-size="0" pane1-class="pr-2" pane2-class="pl-2">
      <template #1>
        <NCard :title="$t('page.manage.menu.title')" :bordered="false" size="small">
          <template #header-extra>
            <NButton quaternary @click="init(null)">
              <template #icon>
                <SvgIcon icon="ic:round-refresh" />
              </template>
            </NButton>
          </template>
          <NInput v-model:value="name" placeholder="请输入菜单名称" clearable />
          <NScrollbar class="m-t-2 max-h-640px min-h-640px">
            <NTree
              :data="menuTree"
              :pattern="name"
              block-line
              key-field="id"
              label-field="name"
              :show-irrelevant-nodes="false"
              class="gap-16px"
              @update-selected-keys="(_key, _option, { node, action }) => handleSelectKeys(node, action)"
            />
          </NScrollbar>
        </NCard>
      </template>
      <template #2>
        <div v-if="menuVisible">
          <NCard title="菜单详情" :bordered="false" size="small" class="mb-2">
            <template #header-extra>
              <NSpace>
                <NButton ghost type="primary" size="small" @click="handleAddMenu()">新增</NButton>
                <NButton ghost type="primary" size="small" @click="handleEditMenu()">
                  {{ $t('common.edit') }}
                </NButton>
                <NPopconfirm placement="bottom" @positive-click="handleDeleteMenu">
                  <template #trigger>
                    <NButton ghost type="error" size="small">
                      {{ $t('common.delete') }}
                    </NButton>
                  </template>
                  {{ $t('common.confirmDelete') }}
                </NPopconfirm>
              </NSpace>
            </template>
            <NDescriptions label-placement="left" size="small" bordered :column="2">
              <NDescriptionsItem label="类型" label-style="width: 100px" content-style="width: 300px">
                <PorDictTag dict-code="system_menu_type" :value="showData.type" value-to-number></PorDictTag>
              </NDescriptionsItem>
              <NDescriptionsItem label="状态" label-style="width: 100px" content-style="width: 300px">
                <PorDictTag dict-code="common_status" :value="showData.status" value-to-number></PorDictTag>
              </NDescriptionsItem>
              <NDescriptionsItem label="名称" label-style="width: 100px" content-style="width: 300px">
                <span class="n-descriptions-item-span">
                  <SvgIcon
                    v-if="showData.icon"
                    :icon="showData.iconType === '1' ? showData.icon : undefined"
                    :local-icon="showData.iconType === '2' ? showData.icon : undefined"
                    class="text-icon"
                  />
                  {{ showData.name }}
                </span>
              </NDescriptionsItem>
              <NDescriptionsItem label="国际化 Key" label-style="width: 100px" content-style="width: 300px">
                {{ showData.i18nKey }}
              </NDescriptionsItem>
              <NDescriptionsItem label="路由名称" label-style="width: 100px" content-style="width: 300px">
                {{ showData.routeName }}
              </NDescriptionsItem>
              <NDescriptionsItem label="路由路径" label-style="width: 100px" content-style="width: 300px">
                {{ showData.routePath }}
              </NDescriptionsItem>
              <NDescriptionsItem label="隐藏菜单" label-style="width: 100px" content-style="width: 300px">
                <PorDictTag dict-code="common_yes_no" :value="showData.hide"></PorDictTag>
              </NDescriptionsItem>
              <NDescriptionsItem label="排序号" label-style="width: 100px" content-style="width: 300px">
                {{ showData.sortRank }}
              </NDescriptionsItem>
              <NDescriptionsItem label="外链" :span="2" label-style="width: 100px" content-style="width: 300px">
                {{ showData.href }}
              </NDescriptionsItem>
            </NDescriptions>
          </NCard>
          <!-- 菜单的实现才显示 -->
          <ButtonListTable v-if="buttonVisible" v-model:parent-id="showData.id as number" :show-data="showData" />
        </div>
        <div v-else>
          <NCard :bordered="false" size="small" class="min-h-250px">
            <NEmpty description="无数据" class="h-full justify-center" />
          </NCard>
        </div>
      </template>
    </NSplit>
    <MenuOperateDrawer
      v-model:visible="menuDrawerVisible"
      :row-data="showData"
      :operate-type="operateType"
      :all-pages="allPages"
      @submitted="data => init(data)"
    />
  </div>
</template>

<style scoped>
.n-descriptions-item {
  display: flex;
  align-items: start;
}

.n-descriptions-item-span {
  display: flex;
  align-items: center;
  gap: 4px;
}

.n-descriptions-item-label {
  width: 100px;
}
</style>
